#include "clock.h"

#ifdef __cplusplus
extern "C"
{
#endif

#define Systick_Enable() SysTick->CTLR = 1
#define Systick_Disable() SysTick->CTLR = 0

  __IO uint32_t uwTick;
  uint32_t uwTickPrio = (1UL << 4U);
  SysTick_Type_Union *SysTickUnon = (SysTick_Type_Union *)SysTick;

  uint32_t SysTick_Config(uint32_t ticks)
  {
    uwTick = 0;


#if defined(CH32V1xx)

    NVIC_SetPriority(SysTicK_IRQn, 0xF0);
    
    Systick_Disable();

    SysTick->CNTL0 = 0;
    SysTick->CNTL1 = 0;
    SysTick->CNTL2 = 0;
    SysTick->CNTL3 = 0;

    SysTick->CMPLR0 = (uint8_t)(ticks & 0xFF);
    SysTick->CMPLR1 = (uint8_t)(ticks >> 8);
    SysTick->CMPLR2 = (uint8_t)(ticks >> 16);
    SysTick->CMPLR3 = (uint8_t)(ticks >> 24);

    SysTick->CMPHR0 = 0;
    SysTick->CMPHR1 = 0;
    SysTick->CMPHR2 = 0;
    SysTick->CMPHR3 = 0;

    Systick_Enable();
        
    NVIC_EnableIRQ(SysTicK_IRQn);

#elif defined(CH32V3xx)

    NVIC_SetPriority(SysTicK_IRQn, 0xF0);

    SysTick->CTLR = 0;
    SysTick->SR   = 0;
    SysTick->CNT  = 0;
    SysTick->CMP  = (ticks * 8) - 1;
    SysTick->CTLR = 0xF;

    NVIC_EnableIRQ(SysTicK_IRQn);

#endif

  }

  /**
   * @brief  Function called to read the current micro second
   * @param  None
   * @retval None
   */
  uint32_t getCurrentMicros(void)
  {

    //  printf("%d  \\ %d ", SysTickUnon->CNTL, SysTickUnon->CMPLR);

    uint32_t m = uwTick;
  #if defined(CH32V1xx)
    const uint32_t tms = SysTickUnon->CMPLR + 1;
    __IO uint32_t u = SysTickUnon->CNTL;
    if ((SysTickUnon->CTRL & (1UL << 16)) == (1UL << 16))
    {
      m = uwTick;
      u = SysTickUnon->CNTL;
    }
    return (m * 1000 + (u * 1000) / tms);
  #elif defined(CH32V3xx)
    const uint64_t tms = SysTick->CMP + 1;
    __IO uint64_t u = SysTick->CNT;
    if ((SysTick->SR & (1UL << 0)) == (1UL << 0))
    {
      m = uwTick;
      u = SysTick->CNT;
    }
    return (m * 1000 + (u * 1000) / tms);
  #else
    return 0;
  #endif
  }

  /**
   * @brief  Function called wto read the current millisecond
   * @param  None
   * @retval None
   */
  uint32_t getCurrentMillis(void)
  {
    return uwTick;
  }

  void noOsSystickHandler()
  {
  }

  void osSystickHandler() __attribute__((weak, alias("noOsSystickHandler")));

  /**
   * @brief  Function called when the tick interruption falls
   * @param  None
   * @retval None
   */
#ifndef __FREERTOS__
  void __func_interrupt SysTick_Handler(void)
  {
#if defined(CH32V1xx)
    SysTick->CTLR = 0x0;
    SysTick->CNTL0 = 0;
    SysTick->CNTL1 = 0;
    SysTick->CNTL2 = 0;
    SysTick->CNTL3 = 0;
    SysTick->CNTH0 = 0;
    SysTick->CNTH1 = 0;
    SysTick->CNTH2 = 0;
    SysTick->CNTH3 = 0;
    SysTick->CTLR = 0x1;
#elif defined(CH32V3xx)
    SysTick->CTLR &= ~(4<<0);
    SysTick->SR   = 0;
    SysTick->CNT  = 0;
    SysTick->CTLR |= (4<<0);
#endif
    clockIncrementTick();
    osSystickHandler();
  }

#endif

  void clockIncrementTick(void)
  {
    uwTick += 1;
  }

#ifdef __cplusplus
}
#endif